#pragma once

#include "ColligereDatabaseHandlerBase.hpp"
#include "ColligereDatabaseItemBase.hpp"

namespace col 
{

////////////////////////////////////////////////////
// Forward declarations
////////////////////////////////////////////////////

class AudioDatabaseEvent;

class Album;
class Artist;

///////////////////////////////////////////////////

struct AudioDatabaseTables
{
	struct Artists
	{
		enum { Name = 1, Country, Homepage }; 
	};
	struct Albums
	{ 
		enum { ParentArtistId = 1, Title, Year, Genre, Format, Condition, 
			IsTrashed, TimeStampAdded, TimeStampUpdated, Status, ExtInfo, 
			Label, CatalogNum, Rating, Tags, PurchasePrice, SellPrice }; 
	};
	struct Tracks
	{ 
		enum  { ParentAlbumId = 1, Num, Title, Length }; 
	};
};

class Track : public DatabaseItemBase
{
public:
	Track();
	Track ( const wxString &rNum, const wxString &rTitle, const wxString &rLen );
	virtual ~Track() { }

	void SetTitle ( const wxString &rTitle );
	void SetLength ( const wxString &rLen );
	void SetNum ( const wxString &rNum );

	const wxString &GetTitle() const;
	const wxString &GetLength() const;
	const wxString &GetNum() const;

	Track *Clone() const;

	const DatabaseTable &GetTableDescriptor() const { return *mpsTableDescr; }
protected:
	void InitializeTableDescriptor();
private:
	static DatabaseTable *mpsTableDescr;
};

class Album : public DatabaseItemBase
{
public:
	//! Default constructor. 
	Album();
	virtual ~Album() { }

	typedef std::deque < Track > TrackDeque;

	const wxString &GetAlbum() const;
	const wxString &GetYear() const;
	const wxString &GetGenre() const;
	const wxString &GetFormat() const;
	const wxString &GetCondition() const;
	const wxString &GetStatus() const;
	const wxString &GetExtInfo() const;
	const wxString &GetTimestampAdded() const;
	const wxString &GetTimestampUpdated() const;
	const wxString &GetLabel() const;
	const wxString &GetCatalogNum() const;
	const wxString &GetRating() const;
	const wxString &GetPurchasePrice() const;
	const wxString &GetSellPrice() const;

	string_deque GetTags() const;

	Album &SetAlbum ( const wxString &rAlbum );
	Album &SetYear ( const wxString &rYear );
	Album &SetGenre ( const wxString &rGenre );
	Album &SetFormat ( const wxString &rType );
	Album &SetCondition ( const wxString &rCondition );
	Album &SetAsTrashed ( bool trashed = true );
	Album &SetStatus ( const wxString &rStatus );
	Album &SetExtInfo ( const wxString &rInfo );
	Album &SetTimestampAdded ( const wxString &rTimestamp );
	Album &SetTimestampUpdated ( const wxString &rTimestamp );
	Album &SetLabel ( const wxString &rLabel );
	Album &SetCatalogNum ( const wxString &rCatNum );
	Album &SetRating ( const wxString &rRating );
	Album &SetTags ( const wxString &rTags );
	Album &SetPurchasePrice ( const wxString &rPrice );
	Album &SetSellPrice ( const wxString &rPrice );

	bool IsTrashed() const;
	
	const Track *GetLastChild() const;

	Track *FindChild ( wxUint32 childId );
	const Track *FindChild ( wxUint32 childId ) const;

	Album *Clone() const;

	const DatabaseTable &GetTableDescriptor() const { return *mpsTableDescr; }
protected:
	void InitializeTableDescriptor();
private:
	static DatabaseTable *mpsTableDescr;
};

class Artist : public DatabaseItemBase
{
public:
	//! Default constructor.
	Artist();

	typedef std::deque < Album > AlbumDeque;

	Artist ( const wxString &rArtist, const wxString &rCountry = wxString(), 
		const wxString &rHomepage = wxString() );

	virtual ~Artist() { }

	const wxString &GetArtist() const;
	const wxString &GetCountry() const;
	const wxString &GetHomepage() const;

	void SetArtist ( const wxString &rArtist );
	void SetCountry ( const wxString &rCountry );
	void SetHomepage ( const wxString &rHomepage );
	
	const Album *GetLastChild() const;
	const Album *GetFirstChild() const;

	Album *FindChild ( wxUint32 childId );
	const Album *FindChild ( wxUint32 childId ) const;

	Artist *Clone() const;
	const DatabaseTable &GetTableDescriptor() const { return *mpsTableDescr; }

	virtual bool operator== ( const Artist &rCmp ) const;
protected:
	void InitializeTableDescriptor();
private:
	static DatabaseTable *mpsTableDescr;
	};

////////////////////////////////////////////////////
// AudioDatabaseHandler
////////////////////////////////////////////////////

/*! @brief An audio database handler.
 **/ 
class AudioDatabaseHandler : public DatabaseHandlerBase
{
public:
	AudioDatabaseHandler();
	virtual ~AudioDatabaseHandler();

	wxUint32 GetTypeId() const;

	//! Commits all changes to the database.
	void CommitChanges();

	void AddItem ( const DatabaseItemBase &rItem );
	void UpdateItem ( const DatabaseItemBase &rItem );

	void SetAlbumAsTrashed ( wxUint32 artistId, wxUint32 albumId, bool trashed = true );

	void DeleteItem ( const DatabaseItemBase &rItem );

	void SetArtistAsTrashed ( wxUint32 artistId );
	void QueryAllItems ( bool forceQueryDatabase = false );
	
	//! Returns the number of changed albums.
	wxUint32 GetChangedItemCount() const;

	const Artist *FindItem ( wxUint32 artistId ) const;
	Artist *FindItem ( wxUint32 artistId );

	const DatabaseItemBaseDeque Search ( const wxString &rTerm, wxUint32 flags ) const;

	const DatabaseItemBaseDeque SearchFromColumn ( const wxString &rTerm,
		bool caseSensitive, const DatabaseTable &rTable,
		const DatabaseTable::Column &rColumn ) const;
	
	const DatabaseItemBaseDeque SearchFromColumn ( const wxRegEx &rRe,
		const DatabaseTable &rTable,
		const DatabaseTable::Column &rColumn ) const;

	typedef AudioDatabaseTables Tables;
private:
	void PostDatabaseEvent ( const DatabaseItemBase *pItem, wxInt32 dbEvtType );
	void PostDatabaseEvent ( wxInt32 commandType );

	void ConnectEventHandlers();

	//! Handles incoming database requests.
	void OnDatabaseItemRequest ( AudioDatabaseEvent &rEvent );
};

typedef Album::TrackDeque AlbumTrackDeque;
typedef Artist::AlbumDeque AlbumDeque;

class AudioDatabaseEvent : public DatabaseEventBase
{
public:
	AudioDatabaseEvent ( wxEventType commandType, wxInt32 id,
		const DatabaseItemBase *pItem );
	AudioDatabaseEvent ( wxEventType commandType, wxInt32 id );
	virtual ~AudioDatabaseEvent() { }
	
	wxEvent *Clone() const;

	const Artist *GetArtist() const;
	const Album *GetAlbum() const;
private:
	/*! @brief Default constructor.
	 *
	 * Only for the DECLARE_DYNAMIC_CLASS macro.
	 **/
	AudioDatabaseEvent() { }

// public:
	DECLARE_DYNAMIC_CLASS ( AudioDatabaseEvent );
};

typedef void ( wxEvtHandler::*AudioDatabaseEventFunction ) ( AudioDatabaseEvent & );

}

// --------------------------------------------------------

#define ColligereAudioDatabaseEventHandlerFunction ( wxObjectEventFunction) \
	( wxEventFunction ) ( col::DatabaseEventFunction ) \
	( col::AudioDatabaseEventFunction )